﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Net.Http;
using System.Threading.Tasks;
using Dpx.Models;
using Dpx.Util;
using Newtonsoft.Json;

namespace Dpx.Services {
    /// <summary>
    /// 今日诗词服务
    /// </summary>
    public class JinrishiciService : ITodayPoetryService {
        // *********** 私有变量

        /// <summary>
        /// 偏好存储
        /// </summary>
        private readonly IPreferenceStorage _preferenceStorage;


        /// <summary>
        /// 诗词存储。
        /// </summary>
        private readonly IPoetryStorage _poetryStorage;

        /// <summary>
        /// 警告服务
        /// </summary>
        private readonly IAlertService _alertService;

        /// <summary>
        /// 今日诗词Token键。
        /// </summary>
        public const string JinrishiciTokenKey =
            nameof(JinrishiciService) + ".Token";

        /// <summary>
        /// 今日诗词服务器。
        /// </summary>
        private const string Server = "今日诗词服务器";

        /// <summary>
        /// Token URL
        /// </summary>
        public const string TokenUrl = "https://v2.jinrishici.com/token";


        // *********** 实现方法

        /// <summary>
        /// 获取今日诗词
        /// </summary>
        /// <returns></returns>
        public async Task<TodayPoetry> GetTodayPoetryAsync() {
            var token = await GetTokenAsync();
            if (string.IsNullOrEmpty(token)) {
                return await GetRandomPoetryAsync();
            }

            using var httpClient = new HttpClient();
            var headers = httpClient.DefaultRequestHeaders;
            headers.Add("X-User-Token", token);

            HttpResponseMessage response;
            try {
                response =
                    await httpClient.GetAsync(
                        "https://v2.jinrishici.com/sentence");
                response.EnsureSuccessStatusCode();
            }
            catch (Exception e) {
                _alertService.ShowAlert(
                    ErrorMessages.HTTPCLIENTERRORTITLE,
                    ErrorMessages.HttpClientErrorMessage(Server, e.Message),
                    ErrorMessages.HTTPCLIENTERRORBUTTON);
                return await GetRandomPoetryAsync();
            }

            var json = await response.Content.ReadAsStringAsync();
            var jinrishiciSentence =
                JsonConvert.DeserializeObject<JinrishiciSentence>(json);

            return new TodayPoetry {
                Snippet = jinrishiciSentence.Data.Content,
                Name = jinrishiciSentence.Data.Origin.Title,
                Dynasty = jinrishiciSentence.Data.Origin.Dynasty,
                AuthorName = jinrishiciSentence.Data.Origin.Author,
                Content = string.Join("\n",
                    jinrishiciSentence.Data.Origin.Content),
                Translation = jinrishiciSentence.Data.Origin.Translate == null
                    ? ""
                    : string.Join("\n",
                        jinrishiciSentence.Data.Origin.Translate),
                Source = TodayPoetrySources.JINRISHICI
            };
        }

        /// <summary>
        /// 获得Token
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetTokenAsync() {
            var result = _preferenceStorage.Get(JinrishiciTokenKey, string.Empty);
            if (!string.IsNullOrWhiteSpace(result)) {
                return result;
            }

            // http v1
            using var httpClient = new HttpClient();
            HttpResponseMessage response;
            try {
                response = await httpClient.GetAsync(TokenUrl);
            }
            catch (Exception e) {
                _alertService.ShowAlert(
                    ErrorMessages.HTTPCLIENTERRORTITLE,
                    ErrorMessages.HttpClientErrorMessage(Server, e.Message),
                    ErrorMessages.HTTPCLIENTERRORBUTTON);
                return string.Empty;
            }

            var json = await response.Content.ReadAsStringAsync();
            var tokenObject = JsonConvert.DeserializeObject<JinrishiciToken>(json);

            // 存储Token
            Debug.Assert(tokenObject != null, nameof(tokenObject) + " != null");
            _preferenceStorage.Set(JinrishiciTokenKey, tokenObject.data);
            return tokenObject.data;
        }

        /// <summary>
        /// 获得随机诗词。
        /// </summary>
        public async Task<TodayPoetry> GetRandomPoetryAsync() {
            var poetries = await _poetryStorage.GetPoetriesAsync(
                Expression.Lambda<Func<Poetry, bool>>(Expression.Constant(true),
                    Expression.Parameter(typeof(Poetry), "p")),
                new Random().Next(PoetryStorage.NumberPoetry), 1);
            var poetry = poetries[0];
            return new TodayPoetry {
                Snippet = poetry.Snippet,
                Name = poetry.Name,
                Dynasty = poetry.Dynasty,
                AuthorName = poetry.AuthorName,
                Content = poetry.Content,
                Translation = poetry.Translation,
                Source = TodayPoetrySources.LOCAL
            };
        }

        // *********** 构造函数

        /// <summary>
        /// 今日诗词服务
        /// </summary>
        /// <param name="preferenceStorage">偏好存储</param>
        /// <param name="poetryStorage">诗词存储。</param>
        /// <param name="alertService">警告服务。</param>
        public JinrishiciService(IPreferenceStorage preferenceStorage, IPoetryStorage poetryStorage,
            IAlertService alertService) {
            _preferenceStorage = preferenceStorage;
            _poetryStorage = poetryStorage;
            _alertService = alertService;
        }
    }

    public class JinrishiciToken {
        /// <summary>
        /// Token
        /// </summary>
        public string data { get; set; }
    }

    public class JinrishiciOrigin {
        public string Title { get; set; }
        public string Dynasty { get; set; }
        public string Author { get; set; }
        public List<string> Content { get; set; }
        public List<string> Translate { get; set; }
    }

    public class JinrishiciData {
        public string Content { get; set; }
        public JinrishiciOrigin Origin { get; set; }
    }

    public class JinrishiciSentence {
        public JinrishiciData Data { get; set; }
    }
}